<?php

/**
 * Управление правами и полномочиями пользователей и групп.
 */
class AclModel extends DbModel {

    protected $_name = 'users';

    /**
     * Возвращает всех пользователей, если параметр $id не задан. Если задан, то
     * возращает конкретного пользователя.
     *
     * @param integer $id #ID пользователя
     * @return mixed
     */
    public function getUsers($id = 0) {
        if ($id > 0) {
            $select = $this->_db->select()->from(PREFIX . 'users')->where('id = ?', $id);
            $res = $this->_db->fetchRow($select);
        } else {
            $select = $this->_db->select()->from(PREFIX . 'users');
            $res = $this->_db->fetchAll($select);
        }
        return $res;
    }

    public function authentification($login, $password) {
        $f = new Zend_Filter_StripTags();
        $login = $f->filter($login);
        $password = $f->filter($password);
        if ($login == '' || $password == '')
            return false;
        $authAdapter = new Zend_Auth_Adapter_DbTable(
                        Zend_Db_Table::getDefaultAdapter(),
                        'users',
                        'login',
                        'password',
                        'MD5(CONCAT(salt, ?)) AND ' . 'active = 1'
        );
        $auth = Zend_Auth::getInstance();
        $authAdapter->setIdentity($login);
        $authAdapter->setCredential($password);
        $result = $auth->authenticate($authAdapter);
        if ($result->isValid()) {
            $data = $authAdapter->getResultRowObject(null, 'password');    
            /*
             * Получаем список групп в которые входит пользователь
             */
            $model = new AclModel();
            $userID = $data->id;
            $pageModel = new PageModel();
            $addons = $pageModel->getAddonsList(null, 'title');
            $model->updateTimeLogin($userID);
            $acls_array = array();
            $acls_allow = false;
            if ($userID <> 1) { //Если не администратор
                $groups = $model->getGroupsByUser($userID);
                foreach ($groups as $group) {
                    $group_array[] = $group->id;
                    $groupAcls = explode('|', $group->acls);
                    foreach ($groupAcls as $acl) {
                        if ($acl)
                            $acls_allow->{$addons[$acl]} = true;
                    }
                }
            } else {
                //Даем полные права на все
                foreach ($addons as $key => $value) {
                    $acls_allow->{$value} = true;
                }
                
                //Загружаем информацию о последней версии для обновления
                $file = "lastversion";
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_FAILONERROR, 1);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_URL, "http://www.unlabeled.ru/" . $file);
                $version = curl_exec($ch);
                curl_close($ch);
                if ($version) {
                    $current = explode('.', $version, 3);
                    $settingsModel = new SettingsModel();
                    $settingsModel->updateSettings(array(
                        'update' => (int) $current[0] . '.' . (int) $current[1] . '.' . (int) $current[2]
                        ));
                }

            }
            $session = new Zend_Session_Namespace('UnCMS');
            Zend_Session::rememberMe(60 * 60 * 24 * 7);
            $session->groups = $model->getGroupsList();
            $session->acl = $acls_allow;    
            $auth->getStorage()->write($data);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Получение пользователя по его логину
     *
     * @param string $login Логин пользователя
     * @return user object
     */
    public function getUserByLogin($login) {
        $select = $this->_db->select()->from(PREFIX . 'users')->where('login = ?', $login);
        $res = $this->_db->fetchRow($select);
        return $res;
    }

    /**
     * Получение пользователя по его E-mail
     *
     * @param string $email E-mail пользователя
     * @return user object
     */
    public function getUserByEmail($email) {
        $select = $this->_db->select()->from(PREFIX . 'users')->where('email = ?', $email);
        $res = $this->_db->fetchRow($select);
        return $res;
    }

    /**
     * Получение пользователя по "соли"
     *
     * @param string $salt "Соль"
     * @return user object
     */
    public function getUserBySalt($salt) {
        $select = $this->_db->select()->from(PREFIX . 'users')->where('salt = ?', $salt);
        $res = $this->_db->fetchRow($select);
        return $res;
    }

    /**
     * Получение пользователей системы для списков
     *
     * @return array Массив пользователей вида 'id' => name
     */
    public function getUsersList() {
        $select = $this->_db->select()->from(PREFIX . 'users', array('id', 'name'));
        $res = $this->_db->fetchPairs($select);
        return $res;
    }

    /**
     * Получение массива групп для списков
     *
     * @return array Массив групп вида 'id' => name
     */
    public function getGroupsList() {
        $select = $this->_db->select()->from(PREFIX . 'users_groups', array('id', 'name'));
        $res = $this->_db->fetchPairs($select);
        return $res;
    }

    /**
     * Получения групп в которые входит пользователь
     * 
     * @param <type> $uid #ID пользователя
     * return array Группы
     */
    public function getGroupsByUser($uid) {
        $select = 'SELECT ' . PREFIX . 'users_groups.* FROM ' . PREFIX . 'users_entry, ' . PREFIX . 'users_groups WHERE ' . PREFIX . 'users_groups.id = ' . PREFIX . 'users_entry.gid AND ' . PREFIX . "users_entry.uid = " . $uid;
        $res = $this->_db->fetchAll($select);
        return $res;
    }

    /**
     * Возвращает вхождение пользователя/группы.
     * Определяет к каким группам принадлежит пользователь или
     * какие пользователи входят в группу (вариант без второго параметра).
     *
     * @param int $id ID группы или пользователя
     * @param bool $group Указатель на группу, по умолчанию false (возвращает группы пользователя)
     * @return array
     */
    public function getEntry($id = 0, $group = false) {
        if ($group) {
            $select = $this->_db->select()->from(PREFIX . 'users_entry', array('uid'));
            $select->where('gid = ' . $id);
        } else {
            $select = $this->_db->select()->from(PREFIX . 'users_entry', array('gid'));
            $select->where('uid = ' . $id);
        }
        $res = $this->_db->fetchCol($select);
        return $res;
    }

    /**
     * Обновление информации о принадлежности пользователей к группам.
     *
     * @param array $array Массив пользователей/групп
     * @param int $id #ID пользователя/группы
     * @param bool $group Указатель на группу, по умолчанию false (пользователи)
     */
    public function updateEntry($array = array(), $id = 0, $group = false) {
        if ($group) {
            $select = $this->_db->delete(PREFIX . 'users_entry', 'gid = ' . $id);
            foreach ($array as $key => $val) {
                $this->_db->insert(PREFIX . 'users_entry', array('gid' => $id, 'uid' => $val));
            }
        } else {
            $select = $this->_db->delete(PREFIX . 'users_entry', 'uid = ' . $id);
            foreach ($array as $key => $val) {
                $this->_db->insert(PREFIX . 'users_entry', array('uid' => $id, 'gid' => $val));
            }
        }
    }

    /**
     * Получение группы или групп при $id=0
     *
     * @param int $id #ID группы
     * @return mixed
     */
    public function getGroups($id = 0) {
        if ($id > 0) {
            $select = $this->_db->select()->from(PREFIX . 'users_groups')
                            ->where('id = ?', $id)
                            ->order('name ASC');
            $res = $this->_db->fetchRow($select);
        } else {
            $select = $this->_db->select()
                            ->from(PREFIX . 'users_groups')
                            ->order('name ASC');
            $res = $this->_db->fetchAll($select);
        }
        return $res;
    }

    /**
     * Активация пользователя
     *
     * @param string $salt "Соль"
     */
    public function activateUser($salt) {
        $this->update(array('active' => 1), "salt = '" . $salt . "'");
    }

    /**
     * Обновление пароля
     *
     * @param string $id #ID Пользователя
     */
    public function updatePassword($id) {
        $newSalt = md5(uniqid(rand(), 1));
        $config = Zend_Registry::get('config');
        $randStr = '';
        $feed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        for ($i = 0; $i < $config->pass_lenght; $i++) {
            $randStr .= substr($feed, rand(0, strlen($feed) - 1), 1);
        }
        $this->updateUser(array('password' => $randStr), $id);
        return $randStr;
    }

    /**
     * Обновление пользователя или добавление ($id = 0)
     *
     * @param array $data Данные пользователя
     * @param int $id #ID пользователя
     * @return int #ID пользователя
     */
    public function updateUser($data, $id = 0) {
        if (isset($data['password2']))
            unset($data['password2']);
        if (isset($data['password']) && $data['password'] == '') {
            unset($data['password']);
        }
        if ($id > 0 && isset($data['login'])) {
            unset($data['login']);
        }
        if (isset($data['password'])) {
            $salt = md5(uniqid(rand(), 1));
            $data['password'] = md5($salt . $data['password']);
            $data['salt'] = $salt;
        }
        if ($id > 0) {
            $this->update($data, "id = " . $id);
            return $id;
        } else {
            $this->insert($data);
            $uid = $this->_db->lastInsertId();
            $config = Zend_Registry::get('config');
            $this->updateEntry(array($config->group_registered), $uid);
            return $uid;
        }
    }

    /**
     * Обновление группы или добавление ($id = 0)
     *
     * @param array $data Данные группы
     * @param int $id #ID группы
     * @return int #ID группы
     */
    public function updateGroup($data, $id = 0) {
        if ($id > 0) {
            $this->_db->update(PREFIX . 'users_groups', $data, "id = " . $id);
            return $id;
        } else {
            $this->_db->insert(PREFIX . 'users_groups', $data);
            $gid = $this->_db->lastInsertId();
            return $gid;
        }
    }

    /**
     * Обновление прав на объект
     *
     * @param string $object Имя объекста
     * @param int $oid #ID объекта
     * @param array $groups Массив вида Группа => Права
     */
    public function updateAcls($object, $oid, $groups = array()) {
        $permissions = array();
        $sql = $this->_db->delete(PREFIX . 'users_objects', 'oid = ' . $oid . ' AND object = "' . $object . '"');
        foreach ($groups as $key => $val) {
            if ($val > 0) {
                $this->_db->insert(PREFIX . 'users_objects',
                        array(
                            'oid' => $oid,
                            'object' => $object,
                            'gid' => $key,
                            'acl' => $val
                        )
                );
            }
        }
    }

    /**
     * Удаление пользователя
     *
     * @param int $id #ID пользователя
     */
    public function deleteUser($id = 0) {
        $sql = $this->_db->delete(PREFIX . 'users', 'id = ' . $id);
        $sql = $this->_db->delete(PREFIX . 'users_entry', 'uid = ' . $id);
    }

    /**
     * Удаление группы
     *
     * @param int $id #ID группы
     */
    public function deleteGroup($id = 0) {
        $sql = $this->_db->delete(PREFIX . 'users_groups', 'id = ' . $id);
        $sql = $this->_db->delete(PREFIX . 'users_entry', 'gid = ' . $id);
        $sql = $this->_db->delete(PREFIX . 'users_objects', 'gid = ' . $id);
    }

    /**
     * Получение прав на объект
     *
     * @param string $object Имя объекта
     * @param int $oid #ID объекта
     * @return array Массив вида Группа => Права
     */
    public function getAcls($object, $oid = 0) {
        if ($oid > 0) {
            $select = $this->_db->select()->from(PREFIX . 'users_objects', array('gid', 'acl'))
                            ->where('oid = ?', $oid)
                            ->where('object = ?', $object);
            $res = $this->_db->fetchPairs($select);
        } else {
            $select = $this->_db->select()->from(PREFIX . 'users_objects', array('oid', 'gid', 'acl'))
                            ->where('object = ?', $object);
            $res = $this->_db->fetchAll($select);
        }
        if ($res) {
            return $res;
        } else {
            return array();
        }
    }

    /**
     * Получение объекта
     *
     * @param string $object Имя таблицы хранения объекта
     * @param int $oid #ID объекта
     * @return array
     */
    public function getObject($object, $oid) {
        $select = $this->_db->select()->from(PREFIX . $object)->where('id = ?', $oid);
        $res = $this->_db->fetchRow($select);
        if ($res) {
            return $res;
        } else {
            return array();
        }
    }

    /**
     * Обновление времени входа
     *
     * @param int $id #ID пользователя
     */
    public function updateTimeLogin($id) {
        $this->updateUser(array('lastlogin' => date('Y-m-d H:i:s', time())), $id);
    }

}